package bold.deposit.useful.valid;

import bold.storage.core.Record;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 入参校验
 * 支持 Map<String,String>
 * 单个 String
 */
public class $Valid {

    /**
     * id正则检验(16位);
     */
    public static final String ID = "^[1-9][0-9]{15}$";
    /**
     * 不为空
     */
    public static final String NOTNULL = "[^\\s]{1,}";
    /**
     * 邮箱
     */
    public static final String EMAIL = "\\w+(\\.\\w+)*@\\w+(\\.\\w+)+";
    /**
     * 电话号码
     */
    public static final String PHONE = "(^(\\d{2,4}[-_－—]?)?\\d{3,8}([-_－—]?\\d{3,8})?([-_－—]?\\d{1,7})?$)";
    /**
     * 手机号码
     */
    public static final String MOBILE = "^1(3[0-9]|4[57]|5[0-35-9]|7[0135678]|8[0-9])\\d{8}$";
    /**
     * 座机和手机
     */
    public static final String MOBILE_AND_PHONE = "(^(\\d{2,4}[-_－—]?)?\\d{3,8}([-_－—]?\\d{3,8})?([-_－—]?\\d{1,7})?$)|(^0?1[358]\\d{9}$)";
    /**
     * 正整数
     */
    public static final String INTEGER = "^-?(([1-9]\\d*$)|0)";
    /**
     * 正整数正则表达式 >=0 ^[1-9]/d*|0$
     */
    public static final String INTEGER_NEGATIVE = "^[1-9]\\d*|0$";
    /**
     * Double
     */
    public static final String DOUBLE = "^-?([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0)$";
    /**
     * 正Double
     */
    public static final String DOUBLE_NEGATIVE = "^[1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*|0?\\.0+|0$";
    /**
     * 负Double正则表达式 <= 0  ^(-([1-9]\d*\.\d*|0\.\d*[1-9]\d*))|0?\.0+|0$
     */
    public static final String DOUBLE_POSITIVE = "^(-([1-9]\\d*\\.\\d*|0\\.\\d*[1-9]\\d*))|0?\\.0+|0$";
    /**
     * 匹配含两位小最多包数的正数
     */
    public static final String NUMBER_FOR_TWO = "^[0-9]+(.[0-9]{0,2})?$";
    /**
     * 匹配最多包含五位小数的正数
     */
    public static final String NUMBER_FOR_FIVE = "^[0-9]+(.[0-9]{0,5})?$";
    /**
     * 年龄  匹配0-120岁
     */
    public static final String AGE = "^(?:[1-9][0-9]?|1[01][0-9]|120)$";
    /**
     * 邮编 国内6位邮编
     */
    public static final String CODE = "[0-9]\\d{5}(?!\\d)";
    /**
     * 匹配由数字和26个英文字母组成的字符串
     */
    public static final String STR_ENG_NUM = "^[A-Za-z0-9]+";
    /**
     * 匹配由26个英文字母组成的字符串
     */
    public static final String STR_ENG = "^[A-Za-z]+$";
    /***
     * 日期正则 支持：
     *  YYYY-MM-DD
     */
    public static final String DATE_FORMAT1 = "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29)";
    /**
     * URL正则表达式
     * 匹配 http www ftp
     */
    public static final String URL = "^(http|www|ftp|)?(://)?(\\w+(-\\w+)*)(\\.(\\w+(-\\w+)*))*((:\\d+)?)(/(\\w+(-\\w+)*))*(\\.?(\\w)*)(\\?)?" +
            "(((\\w*%)*(\\w*\\?)*(\\w*:)*(\\w*\\+)*(\\w*\\.)*(\\w*&)*(\\w*-)*(\\w*=)*(\\w*%)*(\\w*\\?)*" +
            "(\\w*:)*(\\w*\\+)*(\\w*\\.)*" +
            "(\\w*&)*(\\w*-)*(\\w*=)*)*(\\w*)*)$";
    /**
     * 身份证
     */
    public static final String ID_CARD = "((11|12|13|14|15|21|22|23|31|32|33|34|35|36|37|41|42|43|44|45|46|50|51|52|53|54|61|62|63" +
            "|64|65)[0-9]{4})" +
            "(([1|2][0-9]{3}[0|1][0-9][0-3][0-9][0-9]{3}" +
            "[Xx0-9])|([0-9]{2}[0|1][0-9][0-3][0-9][0-9]{3}))";
    /**
     * 匹配汉字
     */
    public static final String CHINESE = "^[\\u4e00-\\u9fa5]+$";
    /**
     * 提示语
     */
    private static final Map<String, String> MESSAGE = new HashMap<>();


    static {
        MESSAGE.put(NOTNULL, "参数值不为空");
        MESSAGE.put(EMAIL, "邮箱格式错误");
        MESSAGE.put(PHONE, "电话号码格式错误");
        MESSAGE.put(MOBILE, "手机号码格式错误");
        MESSAGE.put(MOBILE_AND_PHONE, "电话号码格式错误");
        MESSAGE.put(INTEGER, "只能为整数");
        MESSAGE.put(AGE, "年龄超出范围");
        MESSAGE.put(CODE, "邮编格式错误");
        MESSAGE.put(STR_ENG_NUM, "非法字符");
        MESSAGE.put(STR_ENG, "必须为字母");
        MESSAGE.put(URL, "连接非法格式");
        MESSAGE.put(ID_CARD, "身份证格式错误");
        MESSAGE.put(CHINESE, "只能为汉字");
        MESSAGE.put(INTEGER_NEGATIVE, "必须是大于零的正整数");
        MESSAGE.put(ID, "id参数格式错误");
    }

    /**
     * 匹配是否符合正则表达式pattern 匹配返回true
     *
     * @param str     匹配的字符串
     * @param pattern 匹配模式
     * @return boolean
     */
    public static boolean Regular(String str, String pattern) {
        if (null == str || str.trim().length() <= 0)
            return false;
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(str);
        return m.matches();
    }

    public static Record Record() {
        return new Record();
    }

    public static String[] array(String... rule) {
        String[] rules = new String[rule.length];
        for (int i = 0; i < rule.length; i++) {
            rules[i] = rule[i];
        }
        return rules;
    }

    /**
     * 校验参数必须不为空
     *
     * @param params 参数
     * @param rules  校验对象 顺序需要注意
     * @throws ValidException
     */
    private static void valid(final Map<String, String> params, Record rules, boolean isNotNull) throws ValidException {
        if (params == null || params.isEmpty()) {
            throw new ValidException("参数为空");
        }

        for (Map.Entry<String, Object> rule : rules.entrySet()) {
            if (isNotNull) {
                if (Objects.isNull(params.get(rule.getKey()))) {
                    throw new ValidException("参数值不为空");
                }
            }

            if (rule.getValue() instanceof String[]) {
                String[] values = (String[]) rule.getValue();
                if (values.length <= 0) {
                    throw new ValidException("校验规则错误参数不为空");
                }
                for (String value : values) {
                    boolean result = Regular(params.get(rule.getKey()), value);
                    if (!result) {
                        throw new ValidException(rule.getKey() + " " + MESSAGE.getOrDefault(value, "参数错误"));
                    }
                }
            } else if (rule.getValue() instanceof String) {
                String value = (String) rule.getValue();
                boolean result = Regular(params.get(rule.getKey()), value);
                if (!result) {
                    throw new ValidException(rule.getKey() + " " + MESSAGE.getOrDefault(rule.getValue(), "参数错误"));
                }
            } else {
                throw new ValidException("校验格式错误");
            }

        }

    }

    /**
     * 必填校验
     *
     * @param params
     * @param rules
     * @throws ValidException
     */
    public static void validAll(final Map<String, String> params, Record rules) throws ValidException {
        valid(params, rules, true);

    }

    /**
     * 值不为空时才校验
     *
     * @param params
     * @param rules
     * @throws ValidException
     */
    public static void valid(final Map<String, String> params, Record rules) throws ValidException {
        valid(params, rules, false);
    }

    /**
     * 可为空的校验
     *
     * @param str
     * @param rules 规则
     */
    public static void valid(final String str, String... rules) {
        if (str != null && str.trim().length() > 0) {
            if (rules.length <= 0) {
                throw new ValidException("校验格式错误");
            }

            for (String value : rules) {
                boolean result = Regular(str, value);
                if (!result) {
                    throw new ValidException(str + " " + MESSAGE.getOrDefault(value, "参数正则校验错误"));
                }
            }
        }
    }

    public static void validNotNull(final String str, String... rules) {
        if (str != null && str.trim().length() > 0) {
            throw new ValidException(str + " " + "参数为空");
        }
        if (rules.length <= 0) {
            throw new ValidException("校验格式错误");
        }

        for (String value : rules) {
            boolean result = Regular(str, value);
            if (!result) {
                throw new ValidException(MESSAGE.getOrDefault(value, "参数正则校验错误"));
            }
        }
    }

    /**
     * 参数都不能为空
     */
    public static void isAnyBlank(String... str) {
        if (StringUtils.isAnyBlank(str)) {
            throw new ValidException("参数不能为空");
        }
    }

    public static void isAnyBlank(Object... str) {
        if (!ObjectUtils.allNotNull(str)) {
            throw new ValidException("参数不能为空");
        }
    }

    public static void isAnyBlank(Map<String, String> params, String... str) {
        if (CollectionUtils.isEmpty(params)) {
            throw new ValidException("参数不能为空");
        }

        for (String s : str) {
            if (StringUtils.isBlank(params.get(s))) {
                throw new ValidException(s + " 参数不能为空");
            }
        }
    }


    /**
     * 测试
     */
    public static void main(String[] args) {
        Map<String, String> params = new HashMap<>();
        params.put("phone", "15123403091");
        params.put("phone2", "121");
        params.put("phone3", "18223277005");

        $Valid.valid("d", $Valid.INTEGER_NEGATIVE);
        //非必填值可为空校验
        $Valid.valid(params,
                new Record().set("phone", $Valid.MOBILE)
                        .set("phone2", new String[]{$Valid.MOBILE, $Valid.NOTNULL})
                        .set("phone3", $Valid.MOBILE_AND_PHONE));

        //必填值不为空校验
        $Valid.validAll(params, $Valid.Record().set("phone", $Valid.MOBILE)
                .set("phone2", $Valid.array($Valid.MOBILE, $Valid.NOTNULL))
                .set("phone3", $Valid.MOBILE_AND_PHONE));


        $Valid.valid("name", $Valid.MOBILE);

        $Valid.valid("18223277005", $Valid.NOTNULL, $Valid.MOBILE);
    }

}
